/*!
 * Web-Forkers
 * http://code.google.com/p/web-workers/
 *
 * version 0.01 PREVIEW
 *
 * Copyright 2010, Evgeny Burzak
 * Licensed under the GPL Version 3 license.
 *
 * An flash backend which converts JavaScript into VM bytecode.
 *
 * Actually this is a stub. But someday it will not.
 *
 * So far you have to compile your code into flash movie by 
 * translating into Haxe or AS code.
 *
 */

package;

import flash.events.Event;
import flash.display.LoaderInfo;

typedef ImageData = {
    var width : Int;
    var height : Int;
    var data : Array<Int>;
}

class Forker {

    public var listeners:Array<Dynamic>;

    public var blobData:Bool;

    public var rawData:Bool;

    // Every message has an unique id, so that event will be fired
    // only once for that message
    public var messageId:Int;

    public function new() {
        var params:Dynamic<String> = flash.Lib.current.loaderInfo.parameters;
        // quick way to trace them all:
        /*trace(params);*/

        listeners = [];

        messageId = -1;

        blobData = false;

        var mc:flash.display.MovieClip = flash.Lib.current;
        mc.addEventListener("enterFrame", listen);
    }

    public function listen(e : Event):Void {
        var params:Dynamic<String> = flash.Lib.current.loaderInfo.parameters;

        var _id = Std.parseInt(params.i);
        if(_id == messageId) return;
        messageId = _id;

        var message:Dynamic = {
            type: null,
            data: null
        }

        if(params.b == "1") 
          blobData = true;
        else
          blobData = false;

        if(params.r == "1") 
          rawData = true;
        else
          rawData = false;

        /*trace(messageId);*/

        if(params.m != "") {
            for (i in 0...listeners.length)
            {
                message.type = listeners[i].type;
                if(listeners[i].type == 'message') {
                    message.data = params.m;
                    Reflect.callMethod(this, Reflect.field(listeners[i], 'handler'), [message]);
                }
            }
        }
    }

    public function addEventListener(type:String, handler:Dynamic, use_capture:Bool):Void {
        listeners.push({
            type : type,
            handler : handler
        });
    }

    // todo serialize message object
    public function postMessage(args:String):Void {
        flash.Lib.fscommand("message", args);
    }

    public function JSON2ImageData(buf : String):ImageData {

        var dataStart : Int = buf.indexOf(";");
        var wh : Array<String> = buf.substr(0, dataStart).split(",");
        var width : Int = Std.parseInt(wh[0]);
        var height : Int = Std.parseInt(wh[1]);
        var data : Array<Int> = [];

        buf = buf.substr(dataStart+1);

        for( i in 0...width*height ) {

          var ofs : Int = i*5,
              mask : Int = buf.charCodeAt(ofs),
              red  : Int = buf.charCodeAt(ofs+1) ^ (mask & 0x2), 
              green : Int = buf.charCodeAt(ofs+2) ^ (mask & 0x4), 
              blue  : Int = buf.charCodeAt(ofs+3) ^ (mask & 0x8), 
              alpha : Int = buf.charCodeAt(ofs+4) ^ (mask & 0x10);

          data[i] = (red << 24) + (green << 16) + (blue << 8) + alpha;
        }

        return {
            width : width,
            height : height,
            data : data
        }
    }

    public function ImageData2JSON(buf : ImageData) : String {
      
        var strBuf : StringBuf = new StringBuf();

        var pix : Int, red : Int, green : Int, blue : Int, alpha : Int,
            mask_red : Int, mask_green : Int, mask_blue : Int, mask_alpha : Int;

        for( i in 0...buf.data.length) 
        {
            pix = buf.data[i];
            red = pix >> 24 & 0xFF;
            green = pix >> 16 & 0xFF;
            blue = pix >> 8 & 0xFF;
            alpha = pix & 0xFF;
            mask_red = (red == 0 ? 1 : 0) << 1;
            mask_green = (green == 0 ? 1 : 0) << 2;
            mask_blue = (blue == 0 ? 1 : 0) << 3;
            mask_alpha = (alpha == 0 ? 1 : 0) << 4;

            strBuf.addChar(mask_red + mask_green + mask_blue + mask_alpha + 1);
            strBuf.addChar(red ^ mask_red);
            strBuf.addChar(green ^ mask_green);
            strBuf.addChar(blue ^ mask_blue);
            strBuf.addChar(alpha ^ mask_alpha);
        }

        return buf.width + "," + buf.height + ";" + strBuf.toString();
    }

}
